﻿using System;
using System.ComponentModel;
using System.Windows;
using LFSRecord2.Model.Undo;
using LFSRecord2.Misc;

namespace LFSRecord2.Model
{
    /// <summary>
    /// Base class for keyframes
    /// </summary>
    public abstract class CustomKeyFrame : DependencyObject, INotifyPropertyChanged, IDisposable
    {
        public int UniqueID { get; set; }
        public CustomKeyFrameTypes KeyFrameType;

        public CompLayerPropertyBase ParentProperty = null;
        public CompLayerBase ParentLayer = null;

        public int SelectionID = 0;
        public bool IsSelectedBackup = false;
        private bool _isSelected = false;
        public bool IsSelected
        {
            get { return (bool)_isSelected; }
            set
            {
                if (_isSelected == value)
                    return;
                _isSelected = value;
                OnPropertyChanged("IsSelected");
                SetKeyImageType();
            }
        }

        public static readonly DependencyProperty KeyImageTypeProperty = DependencyProperty.Register(
            "KeyImageType",
            typeof(KeyImageTypes),
            typeof(CustomKeyFrame),
            new PropertyMetadata(KeyImageTypes.KFNormal)
        );
        public KeyImageTypes KeyImageType
        {
            get { return (KeyImageTypes)GetValue(KeyImageTypeProperty); }
            set { SetValue(KeyImageTypeProperty, value); }
        }

        public void SetKeyImageType()
        {
            // Adjust KeyImage
            if (InterpolationTypeOut == KeyFrameInterpolationTypes.AddElapsed)
            {
                if (IsSelected)
                {
                    if (KeyImageType != KeyImageTypes.KFCannotEaseS)
                        KeyImageType = KeyImageTypes.KFCannotEaseS;
                }
                else
                {
                    if (KeyImageType != KeyImageTypes.KFCannotEase)
                        KeyImageType = KeyImageTypes.KFCannotEase;
                }
            }
            else if (HasHoldValue)
            {
                if (HasEaseIn)
                {
                    if (IsSelected)
                    {
                        if (KeyImageType != KeyImageTypes.KFEaseInHoldS)
                            KeyImageType = KeyImageTypes.KFEaseInHoldS;
                    }
                    else
                    {
                        if (KeyImageType != KeyImageTypes.KFEaseInHold)
                            KeyImageType = KeyImageTypes.KFEaseInHold;
                    }
                }
                else
                {
                    if (IsSelected)
                    {
                        if (KeyImageType != KeyImageTypes.KFHoldS)
                            KeyImageType = KeyImageTypes.KFHoldS;
                    }
                    else
                    {
                        if (KeyImageType != KeyImageTypes.KFHold)
                            KeyImageType = KeyImageTypes.KFHold;
                    }
                }
            }
            else if (HasEaseInOut)
            {
                if (IsSelected)
                {
                    if (KeyImageType != KeyImageTypes.KFEaseInOutS)
                        KeyImageType = KeyImageTypes.KFEaseInOutS;
                }
                else
                {
                    if (KeyImageType != KeyImageTypes.KFEaseInOut)
                        KeyImageType = KeyImageTypes.KFEaseInOut;
                }
            }
            else if (HasEaseIn)
            {
                if (IsSelected)
                {
                    if (KeyImageType != KeyImageTypes.KFEaseInS)
                        KeyImageType = KeyImageTypes.KFEaseInS;
                }
                else
                {
                    if (KeyImageType != KeyImageTypes.KFEaseIn)
                        KeyImageType = KeyImageTypes.KFEaseIn;
                }
            }
            else if (HasEaseOut)
            {
                if (IsSelected)
                {
                    if (KeyImageType != KeyImageTypes.KFEaseOutS)
                        KeyImageType = KeyImageTypes.KFEaseOutS;
                }
                else
                {
                    if (KeyImageType != KeyImageTypes.KFEaseOut)
                        KeyImageType = KeyImageTypes.KFEaseOut;
                }
            }
            else
            {
                if (IsSelected)
                {
                    if (KeyImageType != KeyImageTypes.KFNormalS)
                        KeyImageType = KeyImageTypes.KFNormalS;
                }
                else
                {
                    if (KeyImageType != KeyImageTypes.KFNormal)
                        KeyImageType = KeyImageTypes.KFNormal;
                }
            }
        }

        private int _frameNum = 0;
        public int FrameNum
        {
            get { return (int)_frameNum; }
            set
            {
                _frameNum = value;
                OnPropertyChanged("FrameNum");
            }
        }

        public int KeyFrameIndex { get; set; }

        private double _easeInValue = CustomDoubleEase.NoEase;
        public double EaseInValue
        {
            get { return _easeInValue; }
            set
            {
                _easeInValue = value;
                SetKeyImageType();
                OnPropertyChanged("EaseInValue");
                OnPropertyChanged("HasNoEase");
                OnPropertyChanged("HasEaseIn");
                OnPropertyChanged("HasEaseOut");
                OnPropertyChanged("HasEaseInOut");
            }
        }
        private double _easeOutValue = CustomDoubleEase.NoEase;
        public double EaseOutValue
        {
            get { return _easeOutValue; }
            set
            {
                _easeOutValue = value;
                SetKeyImageType();
                OnPropertyChanged("EaseOutValue");
                OnPropertyChanged("HasNoEase");
                OnPropertyChanged("HasEaseIn");
                OnPropertyChanged("HasEaseOut");
                OnPropertyChanged("HasEaseInOut");
            }
        }

        public bool HasNoEase
        {
            get
            {
                return (EaseInValue == CustomDoubleEase.NoEase && EaseOutValue == CustomDoubleEase.NoEase) ? true : false;
            }
        }
        public bool HasEaseIn
        {
            get
            {
                return (EaseInValue != CustomDoubleEase.NoEase && EaseOutValue == CustomDoubleEase.NoEase) ? true : false;
            }
        }
        public bool HasEaseOut
        {
            get
            {
                return (EaseInValue == CustomDoubleEase.NoEase && EaseOutValue != CustomDoubleEase.NoEase) ? true : false;
            }
        }
        public bool HasEaseInOut
        {
            get
            {
                return (EaseInValue != CustomDoubleEase.NoEase && EaseOutValue != CustomDoubleEase.NoEase) ? true : false;
            }
        }

        public bool HasLinearInterpolation
        {
            get
            {
                return (InterpolationTypeOut == KeyFrameInterpolationTypes.Linear) ? true : false;
            }
        }

        public bool HasAddElapsedInterpolation
        {
            get
            {
                return (InterpolationTypeOut == KeyFrameInterpolationTypes.AddElapsed) ? true : false;
            }
        }

        public bool HasHoldValue
        {
            get
            {
                return ((Options & CustomKeyFrameOptions.Hold) > 0) ? true : false;
            }
        }

        KeyFrameInterpolationTypes _interpolationTypeIn;
        public KeyFrameInterpolationTypes InterpolationTypeIn
        {
            get { return _interpolationTypeIn; }
            set
            {
                _interpolationTypeIn = value;
                if (_interpolationTypeOut == KeyFrameInterpolationTypes.Linear && _interpolationTypeIn == KeyFrameInterpolationTypes.Linear)
                    Options |= CustomKeyFrameOptions.AutoBezier;
                OnPropertyChanged("InterpolationTypeIn");
                OnPropertyChanged("HasLinearLinear");
                OnPropertyChanged("HasLinearBezier");
                OnPropertyChanged("HasBezierLinear");
                OnPropertyChanged("HasBezierBezier");
            }
        }
        KeyFrameInterpolationTypes _interpolationTypeOut;
        public KeyFrameInterpolationTypes InterpolationTypeOut
        {
            get { return _interpolationTypeOut; }
            set
            {
                _interpolationTypeOut = value;
                if (_interpolationTypeOut == KeyFrameInterpolationTypes.Linear && _interpolationTypeIn == KeyFrameInterpolationTypes.Linear)
                    Options |= CustomKeyFrameOptions.AutoBezier;
                OnPropertyChanged("InterpolationTypeOut");
                OnPropertyChanged("HasLinearLinear");
                OnPropertyChanged("HasLinearBezier");
                OnPropertyChanged("HasBezierLinear");
                OnPropertyChanged("HasBezierBezier");

                SetKeyImageType();
                OnPropertyChanged("HasLinearInterpolation");
                OnPropertyChanged("HasAddElapsedInterpolation");
            }
        }
        public bool HasLinearLinear
        {
            get
            {
                return (InterpolationTypeIn == KeyFrameInterpolationTypes.Linear &&
                        InterpolationTypeOut == KeyFrameInterpolationTypes.Linear) ? true : false;
            }
        }
        public bool HasLinearBezier
        {
            get
            {
                return (InterpolationTypeIn == KeyFrameInterpolationTypes.Linear &&
                        InterpolationTypeOut == KeyFrameInterpolationTypes.Bezier) ? true : false;
            }
        }
        public bool HasBezierLinear
        {
            get
            {
                return (InterpolationTypeIn == KeyFrameInterpolationTypes.Bezier &&
                        InterpolationTypeOut == KeyFrameInterpolationTypes.Linear) ? true : false;
            }
        }
        public bool HasBezierBezier
        {
            get
            {
                return (InterpolationTypeIn == KeyFrameInterpolationTypes.Bezier &&
                        InterpolationTypeOut == KeyFrameInterpolationTypes.Bezier) ? true : false;
            }
        }

        public bool HasAutoBezier
        {
            get
            {
                return ((Options & CustomKeyFrameOptions.AutoBezier) > 0) ? true : false;
            }
        }

        private CustomKeyFrameOptions _options = CustomKeyFrameOptions.AutoBezier | CustomKeyFrameOptions.BezierCoupled;
        public CustomKeyFrameOptions Options
        {
            get { return (CustomKeyFrameOptions)_options; }
            set
            {
                CustomKeyFrameOptions oldValue = _options;
                _options = value;
                if (oldValue != _options)
                    OnPropertyChanged("Options");
                if (((oldValue ^ _options) & CustomKeyFrameOptions.AutoBezier) > 0)
                    OnPropertyChanged("HasAutoBezier");
                if (((oldValue ^ _options) & CustomKeyFrameOptions.BezierCoupled) > 0)
                    OnPropertyChanged("HasAutoBezier");
                if (((oldValue ^ _options) & CustomKeyFrameOptions.Hold) > 0)
                {
                    SetKeyImageType();
                    OnPropertyChanged("HasHoldValue");
                }
            }
        }

        public double DistanceToNextKeyFrame { get; set; }

        public double BezierTime = 0;

        public event PropertyChangedEventHandler PropertyChanged;

        public virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                PropertyChanged = null;
                ParentProperty = null;
                ParentLayer = null;
            }
        }

        public abstract KeyFrameDataBase DataStructure();

        protected CustomKeyFrame(int frameNum)
        {
            UniqueID = MathHelper.UniqueID;
            _frameNum = frameNum;
            KeyFrameIndex = 0;
            DistanceToNextKeyFrame = 0;
        }
    }
}
